//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-1999  Microsoft Corporation

Module Name:

command.cpp

Abstract:


Notes:


--*/


#include "precomp.h"


//
// Command ctor
//
CCommand::CCommand()
: m_pHandle(NULL),
  m_szCmd(NULL),
  m_szCmdPart2(NULL),
  m_hrCmdID(0),
  m_dwExecTime(0),
  m_dwTimeout(0),
  m_pfnParse(NULL),
  m_pndNotify(NULL),
  m_dwRetries(0),
  m_dwRetriesOnError(0),
  m_dwRetryOnErrorDelay(0),
  m_apiid(APIID_NONE),
  m_pfnParseWithData(NULL),
  m_pParseData(NULL)
{
    // FUNCTION_TRACE(CCommand::CCommand);
}


//
// Command dtor
//
CCommand::~CCommand()
{
    // FUNCTION_TRACE(CCommand::~CCommand);
    delete[] m_szCmd;
    m_szCmd = NULL;
    delete[] m_szCmdPart2;
    m_szCmdPart2 = NULL;
    delete m_pndNotify;
    m_pndNotify = NULL;
}


//
// Set the command data
//
BOOL CCommand::Init(CRilInstanceHandle* const pHandle, const LPCSTR szCmd, const LPCSTR szCmdPart2, const DWORD dwOptions,
                    const DWORD dwExecTime, const DWORD dwTimeout, CNotificationData* const pnd,
                    const PFN_CMD_PARSE pfnParse, const DWORD dwRetries,
                    const DWORD dwRetriesOnError, const DWORD dwRetryOnErrorDelay, const APIID apiid, const PFN_CMD_PARSE_DATA pfnParseWithData, const PVOID pParseData)
{
    FUNCTION_TRACE(CCommand::Init);
    DEBUGCHK(0 != (dwOptions & CMDOPT_NOOP) || szCmd != NULL);

    UINT cbCmd;
    BOOL fRet = FALSE;

    if (szCmd) {
        cbCmd = strlen(szCmd) + 1;
        delete[] m_szCmd;
        m_szCmd = new char[cbCmd];
        if (!m_szCmd) {
            goto Error;
        }
        strncpyz(m_szCmd, szCmd, cbCmd);
    }

    if (szCmdPart2) {
        cbCmd = strlen(szCmdPart2) + 1;
        delete[] m_szCmdPart2;
        m_szCmdPart2 = new char[cbCmd];
        if (!m_szCmdPart2) {
            goto Error;
        }
        strncpyz(m_szCmdPart2, szCmdPart2, cbCmd);
    }

    m_pHandle = pHandle;
    if (m_pHandle) {
        DEBUGCHK(pHandle->GetDevice() != NULL);
        m_hrCmdID = pHandle->GetDevice()->GetNextCmdID();
    }

    m_dwOptions = dwOptions;
    m_dwExecTime = dwExecTime;
    m_dwTimeout = dwTimeout;
    m_pfnParse = pfnParse;
    m_pndNotify = pnd;
    m_dwRetries = dwRetries;
    m_dwRetriesOnError = dwRetriesOnError;
    m_dwRetryOnErrorDelay = dwRetryOnErrorDelay;
    m_apiid = apiid;
    m_pParseData = pParseData;
    m_pfnParseWithData = pfnParseWithData;
    fRet = TRUE;

Error:
    if (!fRet) {
        delete[] m_szCmd;
        m_szCmd = NULL;
    }
    return fRet;
}


//
//
//
BOOL CCommand::Init(CCommand* pCmd)
{
    FUNCTION_TRACE(CCommand::Init);
    return Init(pCmd->m_pHandle, pCmd->m_szCmd, pCmd->m_szCmdPart2, pCmd->m_dwOptions, pCmd->m_dwExecTime, pCmd->m_dwTimeout,
                pCmd->GiveUpNotificationData(), pCmd->m_pfnParse, pCmd->m_dwRetries, 
                pCmd->m_dwRetriesOnError, pCmd->m_dwRetryOnErrorDelay, pCmd->m_apiid, pCmd->m_pfnParseWithData, pCmd->m_pParseData);
}


//
//
//
DWORD CCommand::GetPriority() const
{
    FUNCTION_TRACE(CCommand::GetPriority);
    DWORD dwPriority;

    if (FInit()) {
        dwPriority = CMDPRI_HIGHEST;
    } else if (FDial() || FHangup()) {
        dwPriority = CMDPRI_HIGH;
    } else {
        dwPriority = CMDPRI_NORMAL;
    }
    return dwPriority;
}


void CCommand::SendResponse(const DWORD dwResponseCode, const void* const pBlob, const UINT cbBlob) const
{
    FUNCTION_TRACE(CCommand::SendResponse);
    // Are we supposed to ignore the command response?
    if (!FIgnoreRsp()) {
        // No -- send out the result as a notification
        SYNCBLOCK(g_csClosing);

        // Retrieve the owning handle
        CRilInstanceHandle* pHandle = GetHandle();

        if (pHandle && pHandle->FReadyForNotifications()) {
            // Send out the resposne to the owning handle
            pHandle->Notify(dwResponseCode, GetID(), pBlob, cbBlob);

            // Remove this command from the owning handle's command list
            pHandle->GetCmdList()->Remove(this);
        }
    }
}

void CCommand::SendNotification(const DWORD dwNotifyCode, const void* const pBlob, const UINT cbBlob) const
{
    FUNCTION_TRACE(CCommand::SendNotification);
    // Are we supposed to ignore the command response?
    if (!FIgnoreRsp()) {
        // No -- send out the result as a notification
        SYNCBLOCK(g_csClosing);
 
        // Retrieve the owning handle
        CRilInstanceHandle* pHandle = GetHandle();
 
        if (pHandle && pHandle->FReadyForNotifications()) {
            // Send out the resposne to the owning handle
            pHandle->Notify(dwNotifyCode, S_OK, pBlob, cbBlob);
 
            // Remove this command from the owning handle's command list
            pHandle->GetCmdList()->Remove(this);
        }
    }
}

//
// Requeues self in the command queue if all the
// retry attempts have not been exhausted.
//
BOOL CCommand::RetryCommandOnError()
{
    FUNCTION_TRACE(CCommand::RetryCommandOnError);

    if (m_dwRetriesOnError > 0)
    {
        m_dwRetriesOnError--;
        return RequeueCmdWithDelay(this, m_dwRetryOnErrorDelay);
    }
    else
    {
        return FALSE;
    }
}
